Subroutines and Gosubs

by Alyce Watson

[http://alycesrestaurant.com/]

Home

View 3D

Math for LB

Using the Modem

Functions

Subroutines

Hall of Fame

API Corner

Tip Corner - RUN

Clipart Viewer

User Design Graphics

Sort by Surnames

Many Textboxes

Newsletter help

Index


What is a Subroutine?

A subroutine is also called a subprogram. It is a self-contained section of code that can be called from other parts of the program. It can be called many times. If code that is to be reused many times is placed in a subroutine, the program has fewer lines of code. It is easier to read and to modify. Liberty BASIC has two kinds of subroutines, the GOSUB and the SUB.


GOSUBS

A subroutine that is called by GOSUB [branchLabel] is part of the main program and shares its memory space. It begins with a branch label and ends with the keyword RETURN. When the RETURN keyword is encountered, the program execution returns to the next line after the GOSUB command that called the routine. Here is an example:

Print "Starting program!"
gosub [printHello]
print "Ending program!"
END

[printHello]
print "Hello, you are in a gosub!"
RETURN

GOSUB Rules

  1. A subroutine called by GOSUB must begin with a branch label and end in RETURN.
  2. The program must not fall into a GOSUB subroutine. The subroutine must be called explicitly. A WAIT, END, or GOTO statement must be used in the code before the branch label that begins the subroutine, to stop the main program from flowing into the subroutine.
    'WRONG!
    [begin]
    print "Hello World"
    
    [myGosub]
    print "I've visited a gosub!"
    RETURN
    '
    'Right:
    print "Hello World"
    WAIT
    
    [myGosub]
    print "I've visited a gosub!"
    RETURN
    
    
  3. The code must not attempt to exit the GOSUB subroutine with a GOTO [branchLabel]
  4. It is not possible to pass arguments (values) into a GOSUB subroutine.
  5. GOSUB subroutines can "see" all other variables and branch labels in the main program.
  6. GOSUB subroutines cannot "see" variables and branch labels in called subroutines or functions.
  7. GOSUB subroutines can call other GOSUB subroutines, called subroutines, or functions.


Called Subroutines

Called subroutines (subs) differ in many respects from GOSUB subroutines. The general form of a called subroutine is as follows:

Sub SubName arg1, arg2,... argN
    'some code here
End Sub

The sub definition is signalled by the keyword Sub. It is followed by the sub's name, then a list of arguments, separated by commas. The argument list must not be placed inside of parentheses. The next lines contain whatever code routine is performed by the sub. The sub definition must end with End Sub.

The Argument List

The arguments may be string, numeric, or a mixture of both. They may be literal values, variables, or expressions. The arguments must be separated by commas. These arguments are actually variables that are local to the sub. They can be used in code contained in the sub. When the sub ends, the variables no longer have any value. A sub can exist without arguments, in which case the sub name is not followed by anything.

The names given to the argument variables in the sub definition represent variables that are local to the sub. When the sub is called, whatever literal value, expression or variable is contained within the commas will be evaluated and given the corresponding name in the argument list. See the following examples for a demonstration of the argument list. Notice in the last example, the variable names used to call the sub are the same names used in the sub, but in a different order. (They are name1$ and name2$.) This doesn't matter, because the argument variables are local to the sub and are not the same variables as the ones with the exact same names used in the main program.

call LongestName "Sam","Patricia"

first$="Carl"
last$="Gundel"
call LongestName last$,first$

name1$="Liberty"
name2$="BASIC"
call LongestName name2$,name1$ 
end

Sub LongestName name1$,name2$
    if len(name1$)>len(name2$) then
        print name1$ + " is the longest."
    else
        print name2$ + " is the longest."
    end if
End Sub

Results in:

Patricia is the longest.

Gundel is the longest.

Liberty is the longest.

Scope

Subs have their own memory space that is separate from the memory of the main portion of the program. Variables and branch labels that exist inside of the sub do not exist in the main program. The main program cannot "see" them. Likewise, subs cannot "see" variables and branch labels that exist in the main program, or in other subs, or functions. The part of the program that can "see" a variable is called its "scope."

Some entities have global scope. That is, they can be seen both inside of subs and in the main program. These things are global in scope: arrays, handles (window and control handles, file handles, DLL handles, communications ports), and structs. In Liberty BASIC 3, if a value from the main program must be visible inside a sub, the value can be held in an array, or passed into the sub as one of the arguments. In Liberty BASIC 4, variables can be declared as GLOBAL, which means that they can be seen from all parts of a program.

Special global status is given to certain default variables used for sizing, positioning, and coloring windows and controls. These include variables WindowWidth, WindowHeight, UpperLeftX, UpperLeftY, ForegroundColor$, BackgroundColor$, ListboxColor$, TextboxColor$, ComboboxColor$, TexteditorColor$. The value of these variables can be seen in any sub. If these variables are used in any way, they become local to the sub. For instance, a window opened inside a sub will open with a width equal to the current WindowWidth. If WindowWidth is used in any way, it becomes local to the sub. As an example, if the sub includes this line:

ww = WindowWidth

WindowWidth no longer has the value it has outside the sub. To test this try the following small demo.

print WindowWidth

call ShowWindowWidth 
end

Sub ShowWindowWidth
    print WindowWidth
End Sub

The results of the program:

320

0

Calling Subs

Subs are called by using the keyword CALL followed by the name of the sub, then a comma separated list of arguments. When the sub exits, program execution returns to the line after the CALL command.

Sub Rules

  1. Subs don't need input arguments.
  2. Sub names are case sensitive. mysub is not the same sub as MySub.
  3. Subs may contain code that calls LB functions or other user-defined functions or subs.
  4. Code should never step into a sub from the main program. A sub should always be called explicitly. Code should not flow into a sub. A WAIT statement, an END statement, or a GOTO [branch] stops program flow from entering a sub.
    'WRONG!
    Call MySub 1,2
    
    Sub MySub num1,num2
    	 print num1+num2
    	End Sub
    '''''''''''''''''''''''''''
    'RIGHT!
    Call MySub 1,2
    wait	'this line halts the program so it doesn't enter the function
    
    Sub MySub num1,num2
    	 print num1+num2
    	End Sub
    '
    

Subs as Event Handlers

Liberty BASIC 4 allows us to use Subs as event handlers. In previous versions of Liberty BASIC, branch labels were used as event handlers. When a Sub is used as an event handler, the argument list contains things like the handle of the control or window that fired the event, the MouseX and MouseY values, and the value of Inkey$. Future newsletters will contain more detailed information about using Subs as event handlers. Here is a small example of a button event handler Sub.

nomainwin
button #main.exit, "Exit", exitClicked, UL, 10, 10
open "Button Example" for window as #main

[loop]
    wait

sub exitClicked buttonhandle$
    notice "The button handle is ";buttonhandle$;"  Goodbye."
    close #main
    end
    end sub


Subroutines in Action

Here is a demo that changes the case of all words in a string so that the first letter is uppercase and the remaining letters are lowercase. Run the little demo to see how it works. Notice that the code inside the sub uses several native LB string functions.

call NameCase "hello world"
call NameCase "CARL GUNDEL"
call NameCase "tiTaNiC"
end

Sub NameCase name$
    nm$=word$(name$,1)
    while nm$<>""
        i = i + 1
        nm$=word$(name$,i)
        first$=upper$(mid$(nm$,1,1))
        rest$=lower$(mid$(nm$,2))
        new$=new$+" "+first$+rest$
    wend
    print "Name is now ";trim$(new$)
    End Sub

Here is a simple numeric sub that prints the average of three values.

call Average 15,88,20
call Average 10,20,30
end
Sub Average num1,num2,num3
    print "Average is ";(num1+num2+num3)/3
    End Sub

Here is the same routine, but this one uses a GOSUB subroutine. GOSUB subroutines do not accept input arguments, but they can "see" values in the main program, because they are actually part of the main program and share its memory space. Note the differences between the two methods:

num1=15
num2=88
num3=20
gosub [Average]

num1=10
num2=20
num3=30
gosub [Average]

end

[Average]
    print "Average is ";(num1+num2+num3)/3
    RETURN


GOSUB or Sub?

Use a GOSUB routine when:

Use a called SUB when:


Home

View 3D

Math for LB

Using the Modem

Functions

Subroutines

Hall of Fame

API Corner

Tip Corner - RUN

Clipart Viewer

User Design Graphics

Sort by Surnames

Many Textboxes

Newsletter help

Index